---
id: local-language
title: 21. 全球化和本地化
sidebar_label: 21. 全球化和本地化（多语言）
---

import useBaseUrl from "@docusaurus/useBaseUrl";

## 21.1 全球化和本地化

**全球化** 是设计支持不同区域性的应用程序的过程。 全球化添加了对一组有关特定地理区域的已定义语言脚本的输入、显示和输出支持。

**本地化** 是将已经针对可本地化性进行处理的全球化应用调整为特定的区域性/区域设置的过程。

通俗来说，就是使应用或系统支持多语言切换。`Furion` 框架提供了完整支持多语言处理的服务。

## 21.2 注册服务

在使用多语言服务之前，必须先注册服务，如：

```cs {4,14-15}
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews()
            .AddAppLocalization();  // 注册多语言
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    // 配置多语言，必须在 路由注册之前
    app.UseAppLocalization();

    app.UseStaticFiles();
    app.UseRouting();

    // 其他中间件
}
```

:::important 特别注意

`app.UseAppLocalization();` 必须在 `app.UseRouting();` 之前注册。

:::

## 21.3 如何使用

### 21.3.1 创建 `Lang.cs` 类

`Furion` 框架采用一种比较特殊的方式动态注入多语言机制，所以必须遵守一个约定，那就是**必须在 `Web启动项目层` 根目录下添加 `Lang.cs` 空类**，也就是和 `Startup.cs` 和 `Progame.cs` 同级。

```cs title="Furion.Web.Entry\Lang.cs"
namespace Furion.Web.Entry
{
    public class Lang { }
}
```

### 21.3.2 配置 `LocalizationSettings`

创建 `Lang.cs` 空类之后，添加 `LocalizationSettings` 配置选项：

```json {2,3}
{
  "LocalizationSettings": {
    "SupportedCultures": ["zh-CN", "en-US"], // 配置支持的语言列表
    "DefaultCulture": "zh-CN" // 配置默认语言，如果不配置，取 SupportedCultures 的第一项
  }
}
```

### 21.3.3 创建 `Resources` 文件夹

接下来在 **`Web启动项目层` 添加 `Resources` 文件夹**，如图：

<img src={useBaseUrl("img/lang1.png")} />

## 21.4 `L` 静态类

`Furion` 框架主要通过 `L` 静态类完整多语言转换，该静态类有以下属性和方法：

- `L.Text[文本]`：转换文本多语言
- `L.Html[HTML代码, 格式化]`：转换 `Html` 多语言
- `L.SetCulture(区域码)`：设置当前语言区域
- `L.GetSelectCulture()`：获取当前的语言区域
- `L.GetCultures()`：获取系统支持的多语言列表

## 21.5 使用例子

通过上面的配置步骤之后，我们就可以通过 `L` 静态类在代码任何位置使用了，如：

### 21.5.1 在类中使用

```cs
// 文本多语言
var apiInterface = L.Text["API 接口"];
var sourceCode = L.Text["源码地址"];

// HTML 标记多语言
var name = L.Html["<b>Hello</b><i> {0}</i>", name];
```

### 21.5.2 在视图中使用

```html {1,6,9}
@using Furion.Localization

<div style="text-align:center;margin-top:50px;">
  <p>让 .NET 开发更简单，更通用，更流行。</p>
  <p>
    <a href="/api">@L.Text["API 接口"]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a
      href="https://gitee.com/dotnetchina/Furion"
      target="_blank"
      >@L.Text["源码地址"]</a
    >
  </p>
</div>
```

### 21.5.3 在验证特性中使用

```cs
[Required(ErrorMessage = "必填消息")]
```

**所有验证特性已经自动支持多语言配置了，无需通过 `L.Text[]` 调用。**

### 21.5.4 在异常消息中使用

```cs {8}
using Furion.FriendlyException;

namespace Furion.Application
{
    [ErrorCodeType]
    public enum ErrorCodes
    {
        [ErrorCodeItemMetadata("用户名不能为空")]
        z1000
    }
}
```

**所有异常消息特性已经自动支持多语言配置了，无需通过 `L.Text[]` 调用。**

```cs
throw Oops.Oh(ErrorCodes.z1000);    // 自动应用多语言
```

## 21.6 创建语言翻译文件

在 `Furion` 框架中，如果没找到对应的语言翻译文件，则自动显示字符串文本，如：

```cs
L.Text["没找到"];   // => 如果设置为英文，但是没有文件，则直接输出 “没找到”
```

### 21.6.1 在 `Resources` 文件夹中创建语言文件

接下来，我们只需要在刚刚的 `Resources` 文件夹中添加 `资源文件` 即可，资源文件命名规则：`Lang.区域码.resx`，如：`Lang.en-US.resx`。

<img src={useBaseUrl("img/lang2.png")} />

<img src={useBaseUrl("img/lang3.png")} />

<p></p>

接下来，只需要把对应语言版本的键值对填写即可。

## 21.7 切换语言

`Furion` 提供了三种语言切换方式进行切换语言：

- `URL 参数` 方式： `?culture=en-US`，**此方式优先级最高**，格式为：`culture=区域码`
- `Cookies` 方式：调用 `L.SetCulture(区域码)` 方式切换
- `客户端浏览器语言自动匹配`：如果前面两种方式都没有设置，**支持自动根据客户端浏览器语言进行匹配。**

### 21.7.1 `URL 参数` 方式

<img src={useBaseUrl("img/lang4.gif")} />

### 21.7.2 `Cookies` 方式

此方式只需要提供一个 `api` 或设置代码即可：

```cs
L.SetCulture("en-US");  // en-US 也可以通过前端传递过来，这样就可以不用 `culture` 参数了，可以自定义参数。
```

这样就可以直接根据客户端存储的 `cookies` 自动切换了。

### 21.7.3 `客户端浏览器语言自动切换`

推荐此方式，可以自动根据浏览器的语言自动配置：

<img src={useBaseUrl("img/lang5.gif")} />

## 21.8 依赖注入方式使用

`Furion` 框架也兼容 `.NET Core` 自带的依赖注入方式，如：

```cs {3,5,7,12}
 public class TestController : Controller
 {
     private readonly IStringLocalizer _localizer;

     public TestController(IStringLocalizerFactory factory)
     {
         _localizer = factory.Create(L.LangType);
     }

     public IActionResult About()
     {
         ViewData["Message"] = _localizer["Your application description page."];
     }
 }
```

## 21.9 `LocalizationSettings` 配置

- `LocalizationSettings` 多语言配置根节点
  - `ResourcesPath`：资源目录，`string` 类型，默认 `Resources`
  - `SupportedCultures`：支持的语言区域码类别，`string[]` 类型
  - `DefaultCulture`：默认语言区域码，如果为空，则取 `SupportedCultures` 第一项

## 21.10 区域码列表

- af 公用荷兰语
- af-ZA 公用荷兰语 - 南非
- sq 阿尔巴尼亚
- sq-AL 阿尔巴尼亚 -阿尔巴尼亚
- ar 阿拉伯语
- ar-DZ 阿拉伯语 -阿尔及利亚
- ar-BH 阿拉伯语 -巴林
- ar-EG 阿拉伯语 -埃及
- ar-IQ 阿拉伯语 -伊拉克
- ar-JO 阿拉伯语 -约旦
- ar-KW 阿拉伯语 -科威特
- ar-LB 阿拉伯语 -黎巴嫩
- ar-LY 阿拉伯语 -利比亚
- ar-MA 阿拉伯语 -摩洛哥
- ar-OM 阿拉伯语 -阿曼
- ar-QA 阿拉伯语 -卡塔尔
- ar-SA 阿拉伯语 - 沙特阿拉伯
- ar-SY 阿拉伯语 -叙利亚共和国
- ar-TN 阿拉伯语 -北非的共和国
- ar-AE 阿拉伯语 - 阿拉伯联合酋长国
- ar-YE 阿拉伯语 -也门
- hy 亚美尼亚
- hy-AM 亚美尼亚的 -亚美尼亚
- az Azeri
- az-AZ-Cyrl Azeri-(西里尔字母的) 阿塞拜疆
- az-AZ-Latn Azeri(拉丁文)- 阿塞拜疆
- eu 巴斯克
- eu-ES 巴斯克 -巴斯克
- be Belarusian
- be-BY Belarusian-白俄罗斯
- bg 保加利亚
- bg-BG 保加利亚 -保加利亚
- ca 嘉泰罗尼亚
- ca-ES 嘉泰罗尼亚 -嘉泰罗尼亚
- zh-HK 华 - 香港的 SAR
- zh-MO 华 - 澳门的 SAR
- zh-CN 华 -中国
- zh-CHS 华 (单一化)
- zh-SG 华 -新加坡
- zh-TW 华 -台湾
- zh-CHT 华 (传统的)
- hr 克罗埃西亚
- hr-HR 克罗埃西亚 -克罗埃西亚
- cs 捷克
- cs-CZ 捷克 - 捷克
- da 丹麦文
- da-DK 丹麦文 -丹麦
- div Dhivehi
- div-MV Dhivehi-马尔代夫
- nl 荷兰
- nl-BE 荷兰 -比利时
- nl-NL 荷兰 - 荷兰
- en 英国
- en-AU 英国 -澳洲
- en-BZ 英国 -伯利兹
- en-CA 英国 -加拿大
- en-CB 英国 -加勒比海
- en-IE 英国 -爱尔兰
- en-JM 英国 -牙买加
- en-NZ 英国 - 新西兰
- en-PH 英国 -菲律宾共和国
- en-ZA 英国 - 南非
- en-TT 英国 - 千里达托贝哥共和国
- en-GB 英国 - 英国
- en-US 英国 - 美国
- en-ZW 英国 -津巴布韦
- et 爱沙尼亚
- et-EE 爱沙尼亚的 -爱沙尼亚
- fo Faroese
- fo-FO Faroese- 法罗群岛
- fa 波斯语
- fa-IR 波斯语 -伊朗王国
- fi 芬兰语
- fi-FI 芬兰语 -芬兰
- fr 法国
- fr-BE 法国 -比利时
- fr-CA 法国 -加拿大
- fr-FR 法国 -法国
- fr-LU 法国 -卢森堡
- fr-MC 法国 -摩纳哥
- fr-CH 法国 -瑞士
- gl 加利西亚
- gl-ES 加利西亚 -加利西亚
- ka 格鲁吉亚州
- ka-GE 格鲁吉亚州 -格鲁吉亚州
- de 德国
- de-AT 德国 -奥地利
- de-DE 德国 -德国
- de-LI 德国 -列支敦士登
- de-LU 德国 -卢森堡
- de-CH 德国 -瑞士
- el 希腊
- el-GR 希腊 -希腊
- gu Gujarati
- gu-IN Gujarati-印度
- he 希伯来
- he-IL 希伯来 -以色列
- hi 北印度语
- hi-IN 北印度的 -印度
- hu 匈牙利
- hu-HU 匈牙利的 -匈牙利
- is 冰岛语
- is-IS 冰岛的 -冰岛
- id 印尼
- id-ID 印尼 -印尼
- it 意大利
- it-IT 意大利 -意大利
- it-CH 意大利 -瑞士
- ja 日本
- ja-JP 日本 -日本
- kn 卡纳达语
- kn-IN 卡纳达语 -印度
- kk Kazakh
- kk-KZ Kazakh-哈萨克
- kok Konkani
- kok-IN Konkani-印度
- ko 韩国
- ko-KR 韩国 -韩国
- ky Kyrgyz
- ky-KZ Kyrgyz-哈萨克
- lv 拉脱维亚
- lv-LV 拉脱维亚的 -拉脱维亚
- lt 立陶宛
- lt-LT 立陶宛 -立陶宛
- mk 马其顿
- mk-MK 马其顿 -FYROM
- ms 马来
- ms-BN 马来 -汶莱
- ms-MY 马来 -马来西亚
- mr 马拉地语
- mr-IN 马拉地语 -印度
- mn 蒙古
- mn-MN 蒙古 -蒙古
- no 挪威
- nb-NO 挪威 (Bokm?l) - 挪威
- nn-NO 挪威 (Nynorsk)- 挪威
- pl 波兰
- pl-PL 波兰 -波兰
- pt 葡萄牙
- pt-BR 葡萄牙 -巴西
- pt-PT 葡萄牙 -葡萄牙
- pa Punjab 语
- pa-IN Punjab 语 -印度
- ro 罗马尼亚语
- ro-RO 罗马尼亚语 -罗马尼亚
- ru 俄国
- ru-RU 俄国 -俄国
- sa 梵文
- sa-IN 梵文 -印度
- sr-SP-Cyrl 塞尔维亚 -(西里尔字母的) 塞尔维亚共和国
- sr-SP-Latn 塞尔维亚 (拉丁文)- 塞尔维亚共和国
- sk 斯洛伐克
- sk-SK 斯洛伐克 -斯洛伐克
- sl 斯洛文尼亚
- sl-SI 斯洛文尼亚 -斯洛文尼亚
- es 西班牙
- es-AR 西班牙 -阿根廷
- es-BO 西班牙 -玻利维亚
- es-CL 西班牙 -智利
- es-CO 西班牙 -哥伦比亚
- es-CR 西班牙 - 哥斯达黎加
- es-DO 西班牙 - 多米尼加共和国
- es-EC 西班牙 -厄瓜多尔
- es-SV 西班牙 - 萨尔瓦多
- es-GT 西班牙 -危地马拉
- es-HN 西班牙 -洪都拉斯
- es-MX 西班牙 -墨西哥
- es-NI 西班牙 -尼加拉瓜
- es-PA 西班牙 -巴拿马
- es-PY 西班牙 -巴拉圭
- es-PE 西班牙 -秘鲁
- es-PR 西班牙 - 波多黎各
- es-ES 西班牙 -西班牙
- es-UY 西班牙 -乌拉圭
- es-VE 西班牙 -委内瑞拉
- sw Swahili
- sw-KE Swahili-肯尼亚
- sv 瑞典
- sv-FI 瑞典 -芬兰
- sv-SE 瑞典 -瑞典
- syr Syriac
- syr-SY Syriac-叙利亚共和国
- ta 坦米尔
- ta-IN 坦米尔 -印度
- tt Tatar
- tt-RU Tatar-俄国
- te Telugu
- te-IN Telugu-印度
- th 泰国
- th-TH 泰国 -泰国
- tr 土耳其语
- tr-TR 土耳其语 -土耳其
- uk 乌克兰
- uk-UA 乌克兰 -乌克兰
- ur Urdu
- ur-PK Urdu-巴基斯坦
- uz Uzbek
- uz-UZ-Cyrl Uzbek-(西里尔字母的) 乌兹别克斯坦
- uz-UZ-Latn Uzbek(拉丁文)- 乌兹别克斯坦
- vi 越南
- vi-VN 越南 -越南

## 21.11 反馈与建议

:::note 与我们交流

给 Furion 提 [Issue](https://gitee.com/dotnetchina/Furion/issues/new?issue)。

:::

---

:::note 了解更多

想了解更多 `多语言` 知识可查阅 [ASP.NET Core - 全局化和本地化](https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/localization?view=aspnetcore-5.0) 章节。

:::
